//
//  Tile.m
//  Mockup
//
//  Created by Bernardo Quibiana on 2/20/10.
//  Copyright 2010 Mac-Easy@USC. All rights reserved.
//

#import "Tile.h"
#import "Sound.h"

@implementation Tile

@synthesize type;
@synthesize pos;
@synthesize containerView;
@synthesize mainImage, backImage;

//BOOL readyThingAgain = TRUE;

-(id) initWithPosition: (struct point_t) _pos andType: (tile_t) _type{
	if(self = [super init]){
		self.pos = _pos;
		self.type = _type;
		CGRect rect = kStdTileFrame;
		CGRect frame = CGRectMake((_pos.x - 1) * rect.size.width + rect.origin.x,
								  (_pos.y - 1) * rect.size.height + rect.origin.y, 
								  rect.size.width, rect.size.height);
		//NSLog(@"Board: (col:%d, row:%d)\tView: (x:%f, y:%f)", _pos.x, _pos.y, frame.origin.x, frame.origin.y);
		self.containerView = [[[UIView alloc] initWithFrame:frame] autorelease];
		
		frame = CGRectMake(0.0, 0.0, rect.size.width, rect.size.height);
		self.mainImage = [[[UIImageView alloc] initWithFrame:frame] autorelease];
		self.mainImage.image = [Tile imageForTileType: _type];
		
		self.backImage = [[[UIImageView alloc] initWithFrame:frame] autorelease];
		self.backImage.image = [Tile imageForTileType:_type];
		
		[self.containerView addSubview: self.mainImage];

		self.mainImage.animationImages = [NSArray arrayWithObjects:
										  [UIImage imageNamed:@"poof1.png"],
										  [UIImage imageNamed:@"poof2.png"], 
										  [UIImage imageNamed:@"poof3.png"],
										  [UIImage imageNamed:@"poof4.png"],
										  [UIImage imageNamed:@"poof5.png"], nil];
		self.mainImage.animationDuration = kTilePoofDuration;
		
		self.backImage.animationImages = [Tile poofAnimationImages];
		self.backImage.animationDuration = kTilePoofDuration;
		
		initial = CGPointMake(self.containerView.center.x, self.containerView.center.y);
		final = CGPointMake(self.containerView.center.x, self.containerView.center.y);
		falling = NO;
		ascending = NO;
	}
	return self;
}

-(void) updateImagePos {
	//CGRect rect = kStdTileFrame;
	//CGPoint center;
	//center.x = (self.pos.x + 0.5)* rect.size.width + rect.origin.x;
	//center.y = (self.pos.y + 0.5)* rect.size.height + rect.origin.y;
	//self.containerView.center = center;
}

-(void) updateImage {
	if ([self.backImage superview])
	{
		self.mainImage.image = [Tile imageForTileType: type];
		[self.backImage removeFromSuperview];
		[self.containerView addSubview: self.mainImage];
	}
	else {	
		self.backImage.image = [Tile imageForTileType: type];
		[self.mainImage removeFromSuperview];
		[self.containerView addSubview: self.backImage];
	}
}

-(void) switchToType:(tile_t)newType {
	self.type = newType;
	[self updateImage];
}


-(void) animateFlipToTile: (tile_t) _type onDirection: (direction_t) direction {
	/*
	if ([self.backImage superview]) {
		self.mainImage.image = [Tile imageForTileType: _type];
	} else {
		self.backImage.image = [Tile imageForTileType: _type];
	}*/
	printf("Animating from tile type %d to %d on direction %d...\n",self.type, _type, direction);
	
	CGFloat duration = kTileFlipDuration;
	[UIView beginAnimations:nil context:NULL];
	[UIView setAnimationDuration: duration];
	
	switch (direction) {
		case North:
			[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp 
								   forView:self.containerView cache:YES];
			break;
		case South:
			[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown 
								   forView:self.containerView cache:YES];
			break;
		case West:
			[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight 
								   forView:self.containerView cache:YES];
			break;
		case East:
			[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft 
								   forView:self.containerView cache:YES];
			break;
		default:
			break;
	}
	
	if ([self.backImage superview])
	{
		self.mainImage.image = [Tile imageForTileType: _type];
		[self.backImage removeFromSuperview];
		[self.containerView addSubview: self.mainImage];
	}
	else {	
		self.backImage.image = [Tile imageForTileType: _type];
		[self.mainImage removeFromSuperview];
		[self.containerView addSubview: self.backImage];
	}
	
	[UIView commitAnimations];
}

-(void) animatePoofWithDelay: (NSTimeInterval) delay {
	[NSTimer scheduledTimerWithTimeInterval:delay target:self 
								   selector:@selector(startPoofAnimation) 
								   userInfo:nil repeats:NO];
	
}

-(void) startPoofAnimation {
	if ([self.backImage superview])
	{
		[self.backImage startAnimating];
	}
	else {		
		[self.mainImage startAnimating];	
	}
	
	CGFloat timer = kTilePoofDuration;
	[NSTimer scheduledTimerWithTimeInterval:timer target:self 
								   selector:@selector(stopPoofAnimation) 
								   userInfo:nil repeats:NO];
}

-(void) stopPoofAnimation {
	if ([self.backImage superview])
	{
		[self.backImage stopAnimating];
	}
	else {		
		[self.mainImage stopAnimating];	
	}
	[self switchToType:Empty];
}

-(void) shiftWithOffset:(double) offset onDirection:(direction_t) direction{
	 
	CGPoint center = self.containerView.center;
	CGRect rect = kScreenFrame;
	CGRect tile = kStdTileFrame;
	
	rect.size.height += tile.size.height;
	rect.size.width += 2 * tile.size.width;
	
	switch (direction) {
		case North:
			center.y =  (int)(center.y - offset + rect.size.height) % (int)rect.size.height ; 
			break;
		case South:
			center.y = (int)(center.y + offset ) % (int)rect.size.height;
			break;
		case West:
			// transform range from [-40, 320] to [0, 400], apply shift and then transform back
			center.x = ((int)(center.x - offset + tile.size.width + rect.size.width) % (int)rect.size.width) - tile.size.width;
			//center.x = (int)(center.x - offset + rect.size.width) % (int)rect.size.width;
			break;
		case East:
			// transform range from [-40, 320] to [0, 400], apply shift and then transform back
			center.x = ((int)(center.x + offset + tile.size.width) % (int)rect.size.width) - tile.size.width;
			//center.x = ((int)(center.x + offset + 40) % 400) - 40;
			//center.x = (int)(center.x + offset) % (int)rect.size.width;
			break;
		default:
			NSLog(@"Tile::shiftWithOffset <<WARNING>> Invalid direction!");
			return;
	}
	
	self.containerView.center = center;
}

-(void) adjustPosition {
	int sign;
	int numMoves = kTileMinAdjustShift;
	float moveSize = 0.0;
	
	CGPoint center = self.containerView.center;
	
	// find the closest center position
	CGPoint adjustedCenter = [self findAdjustedPosition];
	
	// determine min move distance and then move
	if (center.y != adjustedCenter.y) {
		moveSize = abs(center.y - adjustedCenter.y) / numMoves;
		sign = (adjustedCenter.y  - center.y > 0) ? 1 : -1;
		
		for (int i = 0; i < numMoves; i++) {
			center.y += moveSize * sign;
			self.containerView.center = center;
		}
	} else {
		//printf("Tiles::adjustPosition: nothing to adjust in y coord\n");
	}

	
	if (center.x != adjustedCenter.x) {
		moveSize = abs(center.x - adjustedCenter.x) / numMoves;
		sign = (adjustedCenter.x - center.x > 0) ? 1 : -1;
		
		for (int i = 0; i < numMoves; i++) {
			center.x += moveSize * sign;
			self.containerView.center = center;
		}	
	} else {
		//printf("Tiles::adjustPosition: nothing to adjust in x coord\n");
	}

	
	self.containerView.center = adjustedCenter;	// just to ensure exact position
}

-(struct point_t) viewToGridCoord {
	CGRect rect = kStdTileFrame;
	struct point_t point;
	
	// view to grid
	point.x = (int)((self.containerView.center.x + rect.size.width)/rect.size.width);
	point.y = (int)(self.containerView.center.y/rect.size.height);
	
	return point;
}


-(struct point_t) viewToGridCoord:(CGPoint) viewPosition {
	CGRect rect = kStdTileFrame;
	struct point_t point;
	
	// view to grid
	point.x = (int)((viewPosition.x + rect.size.width)/rect.size.width);
	point.y = (int)(viewPosition.y/rect.size.height);
	
	return point;
}

-(CGPoint) gridToViewCoord:(struct point_t) gridPosition {
	CGRect rect = kStdTileFrame;
	// board to view
	CGPoint coord = CGPointMake((gridPosition.x - 0.5) * rect.size.width, 
								(gridPosition.y - 0.5) * rect.size.height + rect.origin.y);
	
	return coord;
}

-(CGPoint) findAdjustedPosition {
	CGRect rect = kStdTileFrame;
	struct point_t point = [self viewToGridCoord];	
	
	// board to view
	CGPoint coord = CGPointMake((point.x - 0.5) * rect.size.width, 
								(point.y - 0.5) * rect.size.height + rect.origin.y);
	
	return coord;
}

-(struct point_t) getCurBoardPosition {
	return [self viewToGridCoord];
}


-(void) moveUp: (BOOL) animated {
	struct point_t curGridPoint = [self viewToGridCoord];
	struct point_t nextGridPoint = {curGridPoint.x, ((curGridPoint.y > 0) ? curGridPoint.y - 1 : 0)};
	CGRect frame = kStdTileFrame;
	
	initial = self.containerView.center;
	
	if (animated) {
		if (ascending) {
			final.y -= frame.size.height;
		} else {
			ascending = YES;
			final = [self gridToViewCoord: nextGridPoint];
			CGFloat timer = kTileFallDuration;
			timer *= 0.85f;
			[NSTimer scheduledTimerWithTimeInterval:timer target:self 
										   selector:@selector(timedMoveUp:) 
										   userInfo:nil	repeats:YES];
		}
	} else {
		// just change center to upper center
		CGPoint upCenter = [self gridToViewCoord:nextGridPoint];
		self.containerView.center = upCenter;
	}
	
}

-(void) moveDown: (BOOL) animated {
	
	int maxRow = 12;	// ?
	struct point_t curGridPoint = [self viewToGridCoord];
	struct point_t upGridPoint = {curGridPoint.x, ((curGridPoint.y < maxRow) ? curGridPoint.y + 1 : maxRow)};
	CGRect frame = kStdTileFrame;
	
	initial = self.containerView.center;
	
	if (animated) {
		if (self.type != Empty && !falling) {
			//[Sound soundEffect:9];	// moved to Boad::animatTilesFall
		}
		if (falling) {
			// already animating fall
			printf("this tile is already animating fall\n");
			final.y += frame.size.height;
		} else {
			falling = YES;
			final = [self gridToViewCoord: upGridPoint];
			CGFloat timer = kTileFallDuration;
			[NSTimer scheduledTimerWithTimeInterval:timer target:self 
										   selector:@selector(timedMoveDown:) 
										   userInfo:nil	repeats:YES];
		}
	} else {
		// just change center to upper center
		final = [self gridToViewCoord: upGridPoint];
		self.containerView.center = final;
		if (self.type != Empty) {
			[Sound soundEffect:9];
		}
	}
}

-(void) timedMoveUp:(NSTimer *)timer {
	CGPoint center = self.containerView.center;
	int moveSize = kTileFallDistance;
	int dy = abs(center.y - final.y);
	
	if ([timer isValid]) {
		if (dy > moveSize) {
			center.y -= moveSize;
			self.containerView.center = center;
		} else {
			[timer invalidate];
			ascending = NO;
			self.containerView.center = center;
			[self adjustPosition];	// too safe?
		}
	}
}

-(void) timedMoveDown:(NSTimer *)timer{
	CGPoint center = self.containerView.center;
	int moveSize = kTileFallDistance;
	int dy = abs(center.y - final.y);

	if ([timer isValid]) {
		if (dy > moveSize) {
			center.y += moveSize;
			self.containerView.center = center;
		} else {
			[timer invalidate];
			falling = NO;
			self.containerView.center = center;
			[self adjustPosition];	// too safe?
			if (self.type != Empty) {
				//[Sound soundEffect:9];
			}
		}
	}
}

-(void) moveOnDirection:(direction_t)direction animated: (BOOL) animated {
	switch (direction) {
		case North:
			[self moveUp:	animated];
			break;
		case South:
			[self moveDown:	animated];
			break;
		default:
			break;
	}
}

-(BOOL) checkMatch:(Tile *)_tile {
	return self.type == _tile.type;
}

+(UIImage *) imageForTileType: (tile_t) _type{
	// the tile types are: Red, Yellow, Blue, Green, Purple, Teal, Black, White
	//[[UIImageView alloc] initWithImage: [UIImage imageNamed:@"bg.png"]];
	
	UIImage * image;
	switch (_type) {
		case Red:
			image = [UIImage imageNamed:@"G1.Red.png"];		// 0
			break;
		case Yellow:
			image = [UIImage imageNamed:@"G2.Yellow.png"];	// 1
			break;
		case Blue:
			image = [UIImage imageNamed:@"G3.Blue.png"];	// 2
			break;
		case Green:
			image = [UIImage imageNamed:@"G4.Green.png"];	// 3
			break;
		case Purple:
			image = [UIImage imageNamed:@"G5.Purple.png"];	// 4
			break;
		case Teal:
			image = [UIImage imageNamed:@"G6.Teal.png"];	// 5
			break;
		case Black:
			image = [UIImage imageNamed:@"G7.Black.png"];	// 6
			break;
		case White:
			image = [UIImage imageNamed:@"G8.White.png"];	// 7
			break;
		case Empty: 
			image = [UIImage imageNamed:@"G0.Blank.png"];
			break;
		default:
			image = [UIImage imageNamed:@"G1.Red.png"];	// shouldn't happen - ERROR RESPONSE NEEDED
			break;
	}
	
	return image;
}

+(NSArray *) poofAnimationImages {
	return [NSArray arrayWithObjects:
			[UIImage imageNamed:@"poof1.png"],
			[UIImage imageNamed:@"poof2.png"], 
			[UIImage imageNamed:@"poof3.png"],
			[UIImage imageNamed:@"poof4.png"],
			[UIImage imageNamed:@"poof5.png"], nil];
}

+(BOOL) chechMatch:(Tile *) lTile :(Tile *) rTile{
	return lTile.type == rTile.type;
}

@end
